Алгоритм Евклида
HОК(а,б) = а*б/HОД(а,б)
HОД(а,б) определяется по алгоритму Евклида:
Алгоритм 1
while (a<>b) do
begin
if a > b then a := a - b
else b := b - a;
end;
HОД := a;
Алгоритм 2
{Будем считать , что HОД
(0,0) = 0. Тогда HОД (a,b) = HОД (a-b,b) = HОД (a,b-a); HОД
(a,0) = HОД (0,a) = a для всех a,b>=0. }
m := a; n := b;
{инвариант: HОД (a,b) = HОД (m,n); m,n >= 0 }
while not ((m=0) or (n=0)) do
begin
if m >= n then
begin
m := m - n;
end else
begin n := n - m; end;
end;
if m = 0 then begin k := n; end else
begin k := m;end;
{NOD (a,b)=k}
Более интересен для расмотрения второй алгоритм, так как при внесении незначительных изменений мы получим новую задачу. Но для начала следует заметить, что этот алгоритм можно ускорить заменив вычитание на деление с остатком.
m := a; n := b;
while not ((m=0) or (n=0)) do
begin
if m >= n then
begin
m := m mod n;
end else
begin n := n mod m; end;
end;
if m = 0 then begin k := n; end else
begin k := m;end;
Мы получили очень большой выйгрыш по времени. Если не верите можете проверить сами на простом примере а=1000000000;b=1, на обычном компьютере результата с первым алгоритмом вы дождётесь нескоро, а вот второй алгоритм выдаст результат моментально.
Но давайте перейдем к обещанной задачи, а точнее решение Диофантового уравнения. Для тех, кто не знает "Диофантовы уравнения" - это уравнения вида Ax+By=C, где A,B,C целые числа и требуется найти целые решения x,y.
Как ни странно, эта задача решается с помощь алгоритма Евклида.
Прежде всего при помощи него можно найти D = НОД(a,b);Следовательно имеет место уравнение:
Ak + Bl = D
Если D=C, то найдено одно из решений X = k; Y = l;
Вообще, если С = D*q, то A*(kq) + B(*lq) = D*q = C;
Следовательно решение существует только когда C кратно D.
{Даны натуральные а и b, не равные 0 одновременно.
Hайти d = HОД (a,b) и такие целые x и y, что d = a*x + b*y.
Решение. Добавим в алгоритм Евклида переменные p, q, r, s
и впишем в инвариант условия m = p*a + q*b; n = r*a + s*b.}
m:=a; n:=b; p := 1; q := 0; r := 0; s := 1;
{инвариант: HОД (a,b) = HОД (m,n); m,n >= 0
m = p*a + q*b; n = r*a + s*b.}
while not ((m=0) or (n=0)) do begin
if m >= n then begin
m := m - n; p := p - r; q := q - s;
end else begin
n := n - m; r := r - p; s := s - q;
end;
end;
if m = 0 then begin
k :=n; x := r; y := s;
end else begin
k := m; x := p; y := q;
end;
Зная частное решение (X,Y) можно найти все остальные
Xr=X+(B*r)/(НОД(A,B));
Yr=Y-(A*r)/(НОД(A,B));
Попробуйте переделать алгоритм так, чтобы вместо вычитания использовать деление с остатком.
Попробуйте написать вариант алгоритма Евклида, использующий соотношения HОД(2*a, 2*b) = 2*HОД(a,b)
HОД(2*a, b) = HОД(a,b) при нечетном b,не включающий деления с остатком, а использующий лишь деление на 2 и проверку четности. (Число действий должно быть порядка log k для исходных данных, не превосходящих k.)
Решение.
m:= a; n:=b; d:=1;
{HОД(a,b) = d * HОД(m,n)}
while not ((m=0) or (n=0)) do begin
if (m mod 2 = 0) and (n mod 2 = 0) then begin
d:= d*2; m:= m div 2; n:= n div 2;
end else if (m mod 2 = 0) and (n mod 2 = 1) then begin
m:= m div 2;
end else if (m mod 2 = 1) and (n mod 2 = 0) then begin
n:= n div 2;
end else if (m mod 2=1) and (n mod 2=1) and (m>=n)then begin
m:= m-n;
end else if (m mod 2=1) and (n mod 2=1) and (m<=n)then begin
n:= n-m;
end;
end;
{m=0 => ответ=d*n; n=0 => ответ=d*m}
Оценка числа действий: каждое второе действие делит хотя бы одно из чисел m и n пополам.
Сайт управляется системой
uCoz